#include <cstring>
#include <cstdlib>
#include <iostream>
#include "XShellCommand.h"
#include "XUtility.h"
#include "constants.h"
#include "XToken.h"

using namespace std;

int g_xbase_debug_verbose = 0;

#define STRING_IS(src, dst) ( src.length() == strlen( dst ) && strncasecmp( src.c_str(), dst, src.length() ) == 0 )
#define STRING_IS_NOT(src ,dst) (!(STRING_IS(src, dst)))
#define STRING_IS_NULL(str) (str.empty())
#define STRING_IS_NOT_NULL(str) (!(STRING_IS_NULL(str)))

static string format(int i)
{
  char buff[10];
  sprintf(buff, "%d", i);

  return string(buff);
}

#if 1
#define LEXICAL_ERROR(msg) { \
	mErrorMsg = "You have an error in your XBASE SQL syntax near "; \
	mErrorMsg += "'"; \
	mErrorMsg += msg; \
	mErrorMsg += "'"; \
	if ( g_xbase_debug_verbose >= 1 ) {\
		mErrorMsg += "  split[]='"; \
		mErrorMsg += token.getLastSplitChars(); \
		mErrorMsg += "'  ("; \
		mErrorMsg += __FILE__; \
		mErrorMsg += ":"; \
		mErrorMsg += format(__LINE__); \
		mErrorMsg += ")"; \
	} \
	}
#else
#define LEXICAL_ERROR(msg) { \
	mErrorMsg = "You have an error in your XBASE SQL syntax near "; \
	mErrorMsg += "\'"; \
	mErrorMsg += msg; \
	mErrorMsg += "\'"; \
	}
#endif
#define SYNTAX_ERROR(msg) { \
	mErrorMsg += msg; \
	}

#define PARSE_HEX() { \
	ok = false; \
	word=token.getNextWord(); \
	if ( word == "(" ) { \
		for (;;) { \
			word= token.getNextWord( " ,)" ); \
			if ( word == "row" || word == "ROW" ) { \
				mISRowHex = true; \
			} else if ( word == "value" || word == "VALUE" ) { \
				mISValueHex = true; \
			} else if ( word == "column" || word == "COLUMN" ) { \
				mISColumnHex = true; \
			} else if ( word == ")" ) { \
				ok = mISRowHex | mISValueHex | mISColumnHex; \
				break; \
			} else if ( word == "," ) { \
				continue; \
			} else { \
				LEXICAL_ERROR( token.getParsedString() ); \
				return res; \
			} \
		} \
	} else {\
		LEXICAL_ERROR( token.getParsedString() ); \
		return res; \
	} \
	}

#define PARSE_SHOW() { \
	ok = false; \
	mISRowShow = false; \
	mISColumnShow = false; \
	mISValueShow = false; \
	word=token.getNextWord(); \
	if ( word == "(" ) { \
		for (;;) { \
			word= token.getNextWord( " ,)" ); \
			if ( word == "row" || word == "ROW" ) { \
				mISRowShow = true; \
			} else if ( word == "value" || word == "VALUE" ) { \
				mISValueShow = true; \
			} else if ( word == "column" || word == "COLUMN" ) { \
				mISColumnShow = true; \
			} else if ( word == ")" ) { \
				ok = mISRowShow | mISValueShow | mISColumnShow; \
				break; \
			} else if ( word == "," ) { \
				continue; \
			} else { \
				LEXICAL_ERROR( token.getParsedString() ); \
				return res; \
			} \
		} \
	} else {\
		LEXICAL_ERROR( token.getParsedString() ); \
		return res; \
	} \
	}

#define GET_EQ_INT(value, name)  \
	if ( STRING_IS( word, name ) ) { \
		word = token.getNextWord(); \
		if ( STRING_IS_NOT( word, "=" ) ) { \
			LEXICAL_ERROR( token.getParsedString() ); \
			return res; \
		} \
		value = atoll( token.getNextWord( " " ).c_str() ); \
		word = token.getNextWord( " =(" ); \
		continue; \
	}
	
#define GET_EQ_STRING(value, name) \
	if ( STRING_IS( word, name ) ) { \
		word = token.getNextWord(); \
		if ( STRING_IS_NOT( word, "=" ) ) { \
			LEXICAL_ERROR( token.getParsedString() ); \
			return res; \
		} \
		value = token.getNextWord( " " ); \
		word = token.getNextWord( " =(" ); \
		continue; \
 	}

#define GET_INT(value) \
	word = token.getNextWord( " ,)" ); \
	if ( STRING_IS_NULL( word ) ) { \
		LEXICAL_ERROR( token.getParsedString() ); \
		return res; \
	} \
	value = atoll( word.c_str() );

bool XShellCommandCreate::parse(const string& str)
{
	bool res = false;

	string word;
	XGroup group;
	XFamily family;

	bool ok = true;
	bool group_is_ok = false;
	bool family_is_ok = false;
	bool have_group_or_family = false;

	XToken token( str );

	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "table" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	
	word = token.getNextWord( " (" );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res ;
	}
	set_table_name( word );
	
	word = token.getNextWord();
	if ( STRING_IS_NOT( word, "(" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord( " ,)" );
	do {
		if ( group_is_ok ) {
			add_group( group.mName,group.mCompressMethod, group.mCacheRate, group.mBlockSize, group.mMaxNumSstable, group.mMaxSizeSstable, group.mMaxSizeMemtable );
			group_is_ok = false;
		}
		if ( family_is_ok ) {
			add_family( family.mName, family.mGroupName, family.mMaxVersion, family.mMaxTTL, family.mDeadtime );
			family_is_ok = false;
		}

		if ( STRING_IS_NULL( word ) ) {
			if ( !have_group_or_family ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}
			else {
				break;
			}
		}

		if ( STRING_IS( word, "group" ) ) {
			group.mName = token.getNextWord( " " );
			if ( STRING_IS_NULL( group.mName ) ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}
			
			word = token.getNextWord( " " );			
			if ( STRING_IS( word, "qkLZ" ) ) {
				group.mCompressMethod = Group::COMPRESS_QUICK_LZ;
			} else if ( STRING_IS( word, "zlib" ) ) {
				group.mCompressMethod = Group::COMPRESS_ZLIB;
			} else if ( STRING_IS( word, "mLZO" ) ) {
				group.mCompressMethod = Group::COMPRESS_MLZO;
			} else if ( STRING_IS( word, "none" ) ) {
				group.mCompressMethod = Group::COMPRESS_NONE;
			} else {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}

			GET_INT( group.mCacheRate );
			GET_INT( group.mBlockSize );
			GET_INT( group.mMaxNumSstable );
			GET_INT( group.mMaxSizeSstable );
			GET_INT( group.mMaxSizeMemtable );

			group_is_ok = true;
			have_group_or_family = true;
			
			word = token.getNextWord( " ,)" );
		}
		else if ( STRING_IS( word, ")" ) ) {
			ok = true;
			break;
		}
		else if ( STRING_IS( word, "," ) ) {
			word = token.getNextWord( " ,)" );
			continue;
		}
		else {
			family.mName = word;			

			GET_INT( family.mMaxVersion );
			GET_INT( family.mMaxTTL );
			GET_INT( family.mDeadtime );

			word = token.getNextWord( " ,)" );
			if ( STRING_IS_NULL( word ) ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}

			family_is_ok = true;
			have_group_or_family = true;
			if ( word == "," || word == ")" ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}
			family.mGroupName = word;

			word = token.getNextWord( " )" );
		}		
	} while (true);	

	if ( !have_group_or_family ) {
		SYNTAX_ERROR( "A table must have at least 1 column" );
		return res;
	}

	if ( !ok || !have_group_or_family ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	res = true;
	return res;
}
string XShellCommandCreate::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandDrop::parse(const string& str)
{
	bool res = false;

	string word;

	XToken token( str );

	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "table") ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	
	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );

	res = true;
	return res;
}
string XShellCommandDrop::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandDesc::parse(const string& str)
{
	bool res = false;

	string word;

	XToken token( str );

	token.getNextWord( " " );

	word= token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );

	res = true;
	return res;
}
string XShellCommandDesc::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandAlter::parse(const string& str)
{
	bool res = false;

	string word;

	XToken token( str );

	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "table" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	
	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );

	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
 		return res;
	}
	if ( STRING_IS( word, "add" ) ) {
		word = token.getNextWord( " " );
		if ( STRING_IS( word, "family") ) {
			XFamily family;
			family.mName = token.getNextWord( " " );
			if ( STRING_IS_NULL( family.mName ) ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}

			GET_INT( family.mMaxVersion );
			GET_INT( family.mMaxTTL );
			GET_INT( family.mDeadtime );

			word = token.getNextWord( " ,)" );
			if ( STRING_IS_NOT_NULL( word ) ) {
				family.mGroupName = word;
			}
			
			add_family( family.mName, family.mGroupName, family.mMaxVersion, family.mMaxTTL, family.mDeadtime );
		} else if ( STRING_IS( word, "group" ) ) {
			XGroup group;
			group.mName = token.getNextWord( " " );
			if ( STRING_IS_NULL( group.mName ) ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}
			
			word = token.getNextWord( " " );			
			if ( STRING_IS( word, "qkLZ" ) ) {
				group.mCompressMethod = Group::COMPRESS_QUICK_LZ;
			} else if ( STRING_IS( word, "zlib" ) ) {
				group.mCompressMethod = Group::COMPRESS_ZLIB;
			} else if ( STRING_IS( word, "mLZO" ) ) {
				group.mCompressMethod = Group::COMPRESS_MLZO;
			} else if ( STRING_IS( word, "none" ) ) {
				group.mCompressMethod = Group::COMPRESS_NONE;
			} else {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}

			GET_INT( group.mCacheRate );
			GET_INT( group.mBlockSize );
			GET_INT( group.mMaxNumSstable );
			GET_INT( group.mMaxSizeSstable );
			GET_INT( group.mMaxSizeMemtable );
			
			add_group( group.mName, group.mCompressMethod, group.mCacheRate, group.mBlockSize, group.mMaxNumSstable, group.mMaxSizeSstable, group.mMaxSizeMemtable );			
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	} else if ( STRING_IS( word, "drop" ) ) {
		word = token.getNextWord( " " );
		if ( STRING_IS( word, "family" ) ) {
			drop_family( token.getNextWord( " " ) );
		} else if ( STRING_IS( word, "group" ) ) {
			drop_group( token.getNextWord( " " ) );
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	} else {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	res = true;
	return res;
}
string XShellCommandAlter::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandInsert::parse(const string& str)
{
	bool res = false;

	string word;
	vector<string> columnList;
	vector<string> valueList;
	uint64_t timestamp = 0;
	string row;
	string value;
	string column;
	bool ok = true;
	
	mISRowHex =  false;
	mISValueHex =  false;
	mISColumnHex =  false;

	XToken token( str );	

	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "into" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
		
	word = token.getNextWord( " (" );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );
	
	word= token.getNextWord();
	if ( STRING_IS_NOT( word, "(" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	word = token.getNextWord( " ,)" );
	while ( STRING_IS_NOT_NULL( word ) ) {
		if ( STRING_IS( word, ")" ) ) {
			word = token.getNextWord( " (" );
			break;
		}
		else if ( STRING_IS( word, "," ) ) {
			word = token.getNextWord( " )" );
			continue;
		}

		columnList.push_back( word );
		word = token.getNextWord( " ,)" );
	}
	if ( columnList.empty() ) {
		SYNTAX_ERROR( "A table must have at least 1 column" );
		return res;
	}

	if ( STRING_IS_NOT( word, "values" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	word = token.getNextWord();
	if ( STRING_IS_NOT( word, "(" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	word = token.getNextWord( " ,)" );
	while ( STRING_IS_NOT_NULL( word ) ) {
		if ( STRING_IS( word, ")" ) ) {
			word = token.getNextWord( " " );
			break;			
		}
		else if ( STRING_IS( word, "," ) ) {
			word = token.getNextWord( " )" );
			continue;
		}

		valueList.push_back( word );
		word = token.getNextWord( " ,)" );
	}
	if ( valueList.empty() ) {
		SYNTAX_ERROR( "A table must have at least 1 value" );
		return res;
	}
	if ( columnList.size() != valueList.size() ) {
		SYNTAX_ERROR( "Column count doesn't match value count" );
		return res;
	}
	
	if ( STRING_IS_NOT( word, "where" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord( " =" );
	if ( STRING_IS_NOT( word, "row" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord();
	if ( STRING_IS_NOT( word, "=" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	
	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	row = word;

	word = token.getNextWord( " (" );
	do {
		if ( STRING_IS_NULL( word ) || STRING_IS( word, "unhex" ) ) {
			break;
		}

		if ( STRING_IS( word, "timestamp" ) ) {
			timestamp = atoll(token.getNextWord( " " ).c_str());
			word = token.getNextWord( " (" );
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	} while ( false );
	
	if ( STRING_IS_NOT_NULL( word ) ) {
		if ( STRING_IS( word, "unhex" ) ) {
			PARSE_HEX();
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	}

	if ( !ok ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	if ( mISRowHex ) {
		row = XUtility::hex_2_str( row );
	}
	for (uint32_t i = 0; i < valueList.size(); i++) {
		if ( mISValueHex ) {
			valueList[i] = XUtility::hex_2_str( valueList[i] );
		}
		if ( mISColumnHex ) {
			int pos = columnList[i].find( ':' );
			if ( pos > 0 ) {
				columnList[i] = columnList[i].substr( 0, pos ) + XUtility::hex_2_str( columnList[i].substr( pos+1 ) );
			}
		}
		add( valueList[i], row, columnList[i], timestamp );
	}

	res = true;
	return res;
}
string XShellCommandInsert::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandSelect::parse(const string& str)
{
	bool res = false;

	string word;
	bool ok = true;

	XToken token( str );

	mISColumnHex = false;
	mISRowHex = false;
	mISValueHex = false;

	mISColumnShow = true;
	mISRowShow = true;
	mISValueShow = true;

	mUnixtime = false;

	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( word.empty() ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}	
	set_column( word );

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "from" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
		
	word= token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );

	word= token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "where" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res; 
	}
	
	word = token.getNextWord( " =" );
	if ( STRING_IS_NOT( word, "row" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord();
	if ( STRING_IS_NOT( word, "=" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_row( word );

	word = token.getNextWord( " (" );
	while ( STRING_IS_NOT_NULL( word )  ) {
		if ( STRING_IS( word, "hex" ) ) {
			PARSE_HEX();
		} else if ( STRING_IS( word, "show" ) ) {
			PARSE_SHOW();
		} else if ( STRING_IS( word, "unixtime") ) {
			mUnixtime = true;
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}

		word = token.getNextWord( "  (" );
	}
#if 0
	word = token.getNextWord( " (" );
	if ( STRING_IS_NOT_NULL( word ) ) {
		if ( STRING_IS( word, "hex" ) ) {
			PARSE_HEX();
		} else if ( STRING_IS( word, "unixtime") ) {
			mUnixtime = true;
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	}
#endif
	if ( !ok ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	res = true;
	return res;
}
string XShellCommandSelect::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandScan::parse(const string& str)
{
	bool res = false;

	string word;
	string rowStart;
	string rowEnd;
	uint64_t timestamp = 0;
	uint64_t ltimestamp = 0;
	uint64_t otimestamp = 0;
	int option = 0;
	int ttl = 0;
	int version = 1;
	int num = 3;
	bool ok = true;

	XToken token( str );
	
	mISColumnHex = false;
	mISRowHex = false;
	mISValueHex = false;

	mISColumnShow = true;
	mISRowShow = true;
	mISValueShow = true;

	mUnixtime = false;

	token.getNextWord( " " );

	bool sp = false;
	for (;;) {
		word = token.getNextWord( " ," );
		if ( STRING_IS_NULL( word ) ) {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
		if ( STRING_IS( word, "," ) ) {
			if ( !sp ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}
			sp = !sp;
			continue;
		} else if ( STRING_IS( word, "from" ) ) {
			break;
		}

		if ( !sp ) {
			add_column( word );
			sp = !sp;
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	}
#if 0
	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "from" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
#endif
	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );
	
	word = token.getNextWord( " =(" );
	do {	
		if ( STRING_IS_NULL( word ) 
			|| STRING_IS( word, "hex" ) 
			|| STRING_IS( word, "show" ) 
			|| STRING_IS( word, "unixtime" ) ) {
			break;
		}

		GET_EQ_STRING( rowStart, "start" );
		GET_EQ_STRING( rowEnd, "end" );
		GET_EQ_INT( timestamp, "timestamp" );
		GET_EQ_INT( ltimestamp, "latesttimestamp" );
		GET_EQ_INT( otimestamp, "oldesttimestamp" );
		GET_EQ_INT( option, "option" );
		GET_EQ_INT( ttl, "ttl" );
		GET_EQ_INT( version, "version" );
		GET_EQ_INT( num, "num" );

		LEXICAL_ERROR( token.getParsedString() );
		return res;
	} while ( true );	


	while ( STRING_IS_NOT_NULL( word )  ) {
		if ( STRING_IS( word, "hex" ) ) {
			PARSE_HEX();
		} else if ( STRING_IS( word, "show" ) ) {
			PARSE_SHOW();
		} else if ( STRING_IS( word, "unixtime") ) {
			mUnixtime = true;
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}

		word = token.getNextWord( "  (" );
	}

	if ( !ok ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	set_row( rowStart, rowEnd );
	set_option( option );
	set_version( version );
	//set_timestamp( timestamp );
	set_num_row( num );
	set_latesttimestamp( ltimestamp );
	set_oldesttimestamp( otimestamp );
	set_ttl( ttl );

	res = true;
	return res;
}
string XShellCommandScan::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandDelete::parse(const string& str)
{
	bool res = false;

	string word;
	string column;
	string key;
	uint64_t timestamp  =0;
	bool ok = true;
	
	mISRowHex =  false;
	mISValueHex =  false;
	mISColumnHex =  false;

	XToken token( str );
	
	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}	
	column = word;

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "from" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	set_table_name( word );

	word = token.getNextWord( " " );
	if ( STRING_IS_NOT( word, "where" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord( " =" );
	if ( STRING_IS_NOT( word, "row" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word= token.getNextWord();
	if ( STRING_IS_NOT( word, "=" ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	word = token.getNextWord( " " );
	if ( STRING_IS_NULL( word ) ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}
	key = word;

	word = token.getNextWord( " (" );
	do {
		if ( STRING_IS_NULL( word ) || STRING_IS( word, "unhex" ) ) {
			break;
		}

		if ( STRING_IS( word, "timestamp" ) ) {
			timestamp = atoll( token.getNextWord( " " ).c_str() );
			word = token.getNextWord( " (" );
		}
	} while ( false );	
	
	if ( STRING_IS_NOT_NULL( word ) ) {
		if ( STRING_IS( word, "unhex" ) ) {
			PARSE_HEX();
		} else {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		}
	}	

	if ( !ok ) {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	if ( mISRowHex ) {
		key = XUtility::hex_2_str( key );
	}
	if ( mISColumnHex ) {
		int pos = column.find( ':' );
		if ( pos > 0 ) {
			column = column.substr( 0, pos ) + XUtility::hex_2_str( column.substr( pos+1 ) );
		}
	}

	add( "", key, column, timestamp );

	res = true;
	return res;
}
string XShellCommandDelete::errormsg()
{
	return mErrorMsg;
}
bool XShellCommandShow::parse(const string& str)
{
	bool res = false;
	bool ok = false;

	string word;

	mISRowHex =  false;
	mISValueHex =  false;
	mISColumnHex =  false;

	XToken token( str );

	token.getNextWord( " " );

	word = token.getNextWord( " " );
	if ( STRING_IS( word, "tables") ) {
		mTable = word;
	} else if ( STRING_IS( word, "tablets" ) ) {
		mTable = word;
	} else if ( STRING_IS( word, "root") ) {
		mTable = "table";
		mTableName = "root";
	} else if ( STRING_IS( word, "table") || STRING_IS( word, "tablet" ) ) {
		mTable = word;

		mTableName = token.getNextWord( " " );
		if ( STRING_IS_NULL( mTableName ) ) {
			LEXICAL_ERROR( token.getParsedString() );
			return res;
		} else if ( STRING_IS( mTableName, "root" ) ) {
			//
		} else {
	 		word = token.getNextWord( " (" );
			if ( STRING_IS_NOT_NULL( word ) ) {
				if ( STRING_IS( word, "hex" )  ) {
					PARSE_HEX();
				} else {
					LEXICAL_ERROR( token.getParsedString() );
					return res;
				}
			} else {
				ok = true;
			}

			if ( !ok ) {
				LEXICAL_ERROR( token.getParsedString() );
				return res;
			}

			set_row( mTableName+",", mTableName+"-" );
			set_table_name( mTableName );
			set_tablet_name( ROOT_META_TABLET_NAME );
			//set_column( ROOT_META_COLUMN_NAME[RMC_SERVER_ADDRESS] );
			set_column( "info:*" );
			set_num_row( 100 );
		}
	} else {
		LEXICAL_ERROR( token.getParsedString() );
		return res;
	}

	res = true;
	return res;
}
string XShellCommandShow::errormsg()
{
	return mErrorMsg;
}
